﻿/*
 * InternalCoordinate
 * 
 * initial implementation : 29.8.2007
 *
 * Copyright (c) Adam Sida, asida@centrum.cz.
 * All rights reserved.
 * 
 * for license see Petra.Gis.License.txt
 */
using System;
//using System.Collections.Generic;
//using System.Text;
//using Petra.Gis.Geometry;


namespace Petra.Gis.Geometry.Support
{
  /// <summary>
  /// InternalPoint - binary acces to coordlist, support object
  /// contains pointer to coordlist byte[] array and load (or save) specific point
  /// unsafe class, uses poiners
  /// </summary>
  public unsafe class InternalCoordinate : Coordinate
  {

    private CoordinateList _parent;
    private int _index;
    private enum coordOrder { x = 0, y = 1, z = 2 }




    internal InternalCoordinate(CoordinateList oParent, int Index)
    {
      _parent = oParent;
      _index = Index;
    }




    public int index
    {
      get { return _index; }
      set 
      {
        if (value < 0 || value > _parent.Count)
          throw new IndexOutOfRangeException("index out of range");
        _index = value;
      }
    }




    public override double X { get { return get_Ordinate(coordOrder.x); } set { set_Ordinate(value, coordOrder.x); } }
    public override double Y { get { return get_Ordinate(coordOrder.y); } set { set_Ordinate(value, coordOrder.y); } }
    public override double Z { get { return get_Ordinate(coordOrder.z); } set { set_Ordinate(value, coordOrder.z); } }



    public override double lon { get { return get_Ordinate(coordOrder.x); } set { set_Ordinate(value, coordOrder.x); } }
    public override double lat { get { return get_Ordinate(coordOrder.y); } set { set_Ordinate(value, coordOrder.y); } }



    private double get_Ordinate(coordOrder order)
    {
      double tmpOrd;

      fixed (byte* beginCoord = &_parent._buffer[_parent.beginOfCoords])
      {

        if (_parent.dimension == Dimension.dim2D && order == coordOrder.z)
          tmpOrd = 0;   //todo:return null or default z  
        else 
        {
          double* tmpPtr = (double*)(beginCoord + (_parent.coordSize * _index) + (CoordinateList.sizeOfDouble * (int)order));
          tmpOrd = *tmpPtr;
        }
      }
      return tmpOrd;
    }




    private void set_Ordinate(double value, coordOrder order)
    {
      //todo:change, if Z ordinate update request rebuild array
      if (_parent.dimension == Dimension.dim2D && order == coordOrder.z)
        throw new ArgumentException("cannot update 2d coord list with 3d point", "order");

      fixed (byte* beginCoord = &_parent._buffer[_parent.beginOfCoords])
      {
        double* tmpPtr = (double*)beginCoord; //+ (parent.coordSize * index) + (CoordinateList.numberSize * (int)order);
        tmpPtr += ((int)_parent.dimension * _index) +  (int)order;
        *tmpPtr = value;
      }
    }



  }
}
